package cashfree

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/spf13/viper"
	"github.com/wonderivan/logger"
	"io/ioutil"
	"net/http"
	"net/url"
	"payment/app/validator"
	"payment/dao"
	"payment/model"
	"payment/utils"
	"strings"
)

type CashFreeService struct {
	Host             string
	APPID            string
	APPSK            string
	RETRUN_URL       string
	PAY_OUT_URL      string
	PAY_OUT_CLIENTID string
	PAY_OUT_CLIENTSK string
}

func GetCashFree() *CashFreeService {
	return &CashFreeService{
		Host:             viper.GetString("cashfree.HOST"),
		APPID:            viper.GetString("cashfree.APPID"),
		APPSK:            viper.GetString("cashfree.APPSK"),
		RETRUN_URL:       viper.GetString("cashfree.RETURN_URL"),
		PAY_OUT_URL:      viper.GetString("cashfree.PAY_OUT_URL"),
		PAY_OUT_CLIENTID: viper.GetString("cashfree.PAY_OUT_CLIENTID"),
		PAY_OUT_CLIENTSK: viper.GetString("cashfree.PAY_OUT_CLIENTSK"),
	}
}

/**
创建收款支付单
*/
func (cf *CashFreeService) CreateOrder(args validator.PayEntryValidator) (*model.PayEntry, error) {
	orderId := utils.GetOrderId("CF")
	reqData := url.Values{}
	reqData.Set("appId", cf.APPID)
	reqData.Set("secretKey", cf.APPSK)
	reqData.Set("orderId", orderId)
	reqData.Set("orderAmount", fmt.Sprint(args.Amount))
	reqData.Set("orderNote", "")
	reqData.Set("customerPhone", args.Phone)
	reqData.Set("customerName", args.UserName)
	reqData.Set("customerEmail", args.Email)
	reqData.Set("returnUrl", cf.RETRUN_URL)
	reqData.Set("notifyUrl", "")
	requestUrl := fmt.Sprintf("%s%s", cf.Host, "api/v1/order/create")

	header := map[string][]string{
		"Content-Type": {"application/x-www-form-urlencoded"},
	}
	data, err := cf.Request(requestUrl, "POST", "", reqData.Encode(), header)

	logger.Debug("CashFreeService_CreateOrder_Info | orderReq=%+v | err=%v", reqData, err)

	cfResponse := &struct {
		Status      string `json:"status"`
		PaymentLink string `json:"paymentLink"`
		Reason      string `json:"reason"`
	}{}
	err = json.Unmarshal(data, cfResponse)
	if err != nil {
		logger.Error("CashFreeService_CreateOrder_JsonUnmarshal_Err | err=%v", err)
		return nil, err
	}
	//请求成功写入流水
	pE := new(model.PayEntry)
	pE.AppId = args.AppId
	pE.PayChannel = model.CASHFREE
	pE.AppOrderId = args.AppOrderId
	pE.OrderId = orderId
	pE.PaymentOrderId = orderId
	pE.Amount = args.Amount
	pE.UserId = args.UserId
	pE.UserName = args.UserName
	pE.Email = args.Email
	pE.Phone = args.Phone
	pE.ThirdCode = cfResponse.Status
	pE.Status = model.PAYING
	if cfResponse.PaymentLink != "" {
		pE.ThirdDesc = cfResponse.PaymentLink
	} else {
		pE.ThirdDesc = cfResponse.Reason
	}
	engine, err := dao.GetMysql()
	if engine == nil || err != nil {
		logger.Error("CashFreeService_CreateOrder_GetDB_Err | err=%v", err)
		return nil, err
	}
	_, err = engine.Insert(pE)
	if err != nil {
		logger.Error("CashFreeService_CreateOrder_InsertDB_Err | err=%v", err)
		return nil, err
	}
	logger.Debug("CashFreeService_CreateOrder_Request | req=%+v | res=%+v", reqData, cfResponse)
	if cfResponse.Status != "OK" {
		err := errors.New(cfResponse.Reason)
		return nil, err
	}
	return pE, err
}

/**
 * 发起放款
 * param: validator.PayOutValidator entryValidator
 * return: *model.PayOut
 * return: error
 */
func (cf *CashFreeService) PayOut(entryValidator validator.PayOutValidator) (payOut *model.PayOut, err error) {
	//创建认证token
	Authorization := cf.Authorize()
	if Authorization == "" {
		err = errors.New("AuthorizationError")
		return nil, err
	}
	//创建受益人
	benRes := cf.AddBeneficiary(entryValidator, Authorization)
	if !benRes {
		err = errors.New("AuthorizationError")
		return nil, err
	}
	//发起支付

	return
}

/**
 * 获得token
 * return: string
 */
func (cf *CashFreeService) Authorize() string {
	requestUrl := fmt.Sprintf("%s%s", cf.PAY_OUT_URL, "/payout/v1/authorize")
	header := map[string][]string{
		"X-Client-Id":     {cf.PAY_OUT_CLIENTID},
		"X-Client-Secret": {cf.PAY_OUT_CLIENTSK},
	}
	data, err := cf.Request(requestUrl, "POST", "", "", header)
	if err != nil {
		logger.Error("CashFreeService_Authorize_Request_Error | err=%v", err)
		return ""
	}
	fmt.Println(string(data))
	res := new(AuthorizeResponse)
	err = json.Unmarshal(data, res)
	if err != nil {
		logger.Error("CashFreeService_Authorize_JsonUnmarshal_Error | err=%v | res=%v", err, res)
		return ""
	}
	return res.Data.Token
}

/**
 * 添加放款人
 */
func (cf *CashFreeService) AddBeneficiary(entryValidator validator.PayOutValidator, auth string) (bool, string) {
	requestUrl := fmt.Sprintf("%s%s", cf.Host, "/payout/v1/authorize")
	header := map[string][]string{
		"X-Client-Id":     {cf.PAY_OUT_CLIENTID},
		"X-Client-Secret": {cf.PAY_OUT_CLIENTSK},
	}
	data, err := cf.Request(requestUrl, "POST", "", "", header)
	if err != nil {
		logger.Error("CashFreeService_Authorize_Request_Error | err=%v", err)
		return false, ""
	}
	res := &struct {
	}{}
	err = json.Unmarshal(data, res)
	if err != nil {
		logger.Error("CashFreeService_Authorize_JsonUnmarshal_Error | err=%v", err)
		return false, ""
	}

	return false, ""
}

/**
统一请求
*/
func (cf *CashFreeService) Request(url string, method string, contentType string, sendData interface{}, header map[string][]string) (res []byte, err error) {
	client := &http.Client{}
	var req *http.Request
	if contentType == "JSON" {
		data, _ := json.Marshal(sendData)
		reader := bytes.NewBuffer(data)
		req, err = http.NewRequest(method, url, reader)
	} else {
		s := sendData.(string)
		reader := strings.NewReader(s)
		req, err = http.NewRequest(method, url, reader)
	}
	//提交请求
	if err != nil {
		logger.Error("CashFreeService_create_order | url=%v | err=%+v | req=%+v", url, err, sendData)
		return
	}
	req.Header = http.Header(header)
	//处理返回结果
	response, err := client.Do(req)
	if err != nil {
		logger.Error("CashFreeService_request_err | url=%v | err=%+v | req=%+v", url, err, sendData)
		return
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		logger.Error("CashFreeService_response_read_err | url=%v | err=%+v | req=%+v", url, err, sendData)
		return
	}
	defer func() {
		_ = response.Body.Close()
	}()
	return body, nil
}
